package soap.latherqq.util;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.StringTokenizer;

import javax.crypto.Cipher;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;

public class CommonUtil {
	// bean变量的注入
	public static Object getValueInBean(Object obj, String name) {
		Object value = null;
		try {
			value = obj
					.getClass()
					.getMethod("get" + CommonUtil.convertFristToUpperCase(name))
					.invoke(obj);
		} catch (Exception e) {
			e.printStackTrace();
		}
		return value;
	}

	public static String toNull(String val) {
		if (isNull(val)) {
			return "";
		} else {
			return val;
		}
	}

	public static Date stringToDate(String d) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		Date date = null;
		try {
			date = sdf.parse(d);
		} catch (Exception e) {
			date = new Date();
		}
		return date;
	}

	public static String dateToString(Date date) {
		SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
		return sdf.format(date);
	}

	public static String getTime(String format) {
		SimpleDateFormat sdf = new SimpleDateFormat(format);
		Date date = new Date();
		return sdf.format(date);
	}

	public static boolean isNull(String val) {
		if (val == null || "".equals(val) || "null".equals(val)) {
			return true;
		} else {
			return false;
		}
	}

	public static String convertFristToUpperCase(String temp) {
		String frist = temp.substring(0, 1);
		String other = temp.substring(1);
		return frist.toUpperCase() + other;
	}

	/**
	 * MD5计算
	 * 
	 * @param value
	 * @return HEX编码的32个字符MD5结果
	 */
	public static String md5(String value) {
		return Convert.byte2HexStringWithoutSpace(digest("md5",
				value.getBytes()));
	}

	/**
	 * 计算HASH值
	 * 
	 * @param type
	 *            Hash类型
	 * @param bytes
	 *            需计算的字节
	 * @return HASH结果
	 */
	public static byte[] digest(String type, byte[] bytes) {
		try {
			MessageDigest dist = MessageDigest.getInstance(type);
			return dist.digest(bytes);
		} catch (NoSuchAlgorithmException e) {
			throw new IllegalArgumentException("Cannot find digest:" + type, e);
		}
	}

	/**
	 * 使用AES算法解密数据，
	 * 
	 * @param encrypted
	 * @param key
	 *            密钥为128位
	 * @param iv
	 *            加密矢量，增加加密强度
	 * @return
	 */
	public static byte[] AESDecrypt(byte[] encrypted, byte[] key, byte[] iv) {
		try {
			SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
			IvParameterSpec ivSpec = new IvParameterSpec(iv);
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(Cipher.DECRYPT_MODE, skeySpec, ivSpec);
			return cipher.doFinal(encrypted);
		} catch (Exception e) {
			throw new IllegalArgumentException("AESDecrypt failed.", e);
		}
	}

	/**
	 * 使用AES算法解密数据，
	 * 
	 * @param plain
	 *            明文
	 * @param key
	 *            密钥为128位
	 * @param iv
	 *            加密矢量，增加加密强度
	 * @return
	 */
	public static byte[] AESEncrypt(byte[] plain, byte[] key, byte[] iv) {
		try {
			SecretKeySpec skeySpec = new SecretKeySpec(key, "AES");
			IvParameterSpec ivSpec = new IvParameterSpec(iv);
			Cipher cipher = Cipher.getInstance("AES/CBC/PKCS5Padding");
			cipher.init(Cipher.ENCRYPT_MODE, skeySpec, ivSpec);
			return cipher.doFinal(plain);
		} catch (Exception e) {
			throw new IllegalArgumentException("AESDecrypt failed.", e);
		}
	}

	// 一些转换工具
	public static class Convert {
		// 16进制字符数组
		private static char[] hex = new char[] { '0', '1', '2', '3', '4', '5',
				'6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };

		/**
		 * 把字节数组转换成16进制字符串
		 * 
		 * @param b
		 *            字节数组
		 * @return 16进制字符串，每个字节之间空格分隔，头尾无空格
		 */
		public static String byte2HexString(byte[] b) {
			if (b == null)
				return "null";
			else
				return byte2HexString(b, 0, b.length);
		}

		/**
		 * 把字节数组转换成16进制字符串
		 * 
		 * @param b
		 *            字节数组
		 * @param offset
		 *            从哪里开始转换
		 * @param len
		 *            转换的长度
		 * @return 16进制字符串，每个字节之间空格分隔，头尾无空格
		 */
		public static String byte2HexString(byte[] b, int offset, int len) {
			if (b == null)
				return "null";

			// 检查索引范围
			int end = offset + len;
			if (end > b.length)
				end = b.length;

			StringBuffer sb = new StringBuffer();

			for (int i = offset; i < end; i++) {
				sb.append(hex[(b[i] & 0xF0) >>> 4]).append(hex[b[i] & 0xF])
						.append(' ');
			}
			if (sb.length() > 0)
				sb.deleteCharAt(sb.length() - 1);
			return sb.toString();
		}

		/**
		 * 把字节数组转换成16进制字符串
		 * 
		 * @param b
		 *            字节数组
		 * @return 16进制字符串，每个字节没有空格分隔
		 */
		public static String byte2HexStringWithoutSpace(byte[] b) {
			if (b == null)
				return "null";

			return byte2HexStringWithoutSpace(b, 0, b.length);
		}

		/**
		 * 把字节数组转换成16进制字符串
		 * 
		 * @param b
		 *            字节数组
		 * @param offset
		 *            从哪里开始转换
		 * @param len
		 *            转换的长度
		 * @return 16进制字符串，每个字节没有空格分隔
		 */
		public static String byte2HexStringWithoutSpace(byte[] b, int offset,
				int len) {
			if (b == null)
				return "null";

			// 检查索引范围
			int end = offset + len;
			if (end > b.length)
				end = b.length;

			StringBuffer sb = new StringBuffer();

			for (int i = offset; i < end; i++) {
				sb.append(hex[(b[i] & 0xF0) >>> 4]).append(hex[b[i] & 0xF]);
			}
			return sb.toString();
		}

		/**
		 * 转换16进制字符串为字节数组
		 * 
		 * @param s
		 *            16进制字符串，每个字节由空格分隔
		 * @return 字节数组，如果出错，返回null，如果是空字符串，也返回null
		 */
		public static byte[] hexString2Byte(String s) {
			try {
				s = s.trim();
				StringTokenizer st = new StringTokenizer(s, " ");
				byte[] ret = new byte[st.countTokens()];
				for (int i = 0; st.hasMoreTokens(); i++) {
					String byteString = st.nextToken();

					// 一个字节是2个16进制数，如果不对，返回null
					if (byteString.length() > 2)
						return null;

					ret[i] = (byte) (Integer.parseInt(byteString, 16) & 0xFF);
				}
				return ret;
			} catch (Exception e) {
				return null;
			}
		}

		/**
		 * 把一个16进制字符串转换为字节数组，字符串没有空格，所以每两个字符 一个字节
		 * 
		 * @param s
		 * @return
		 */
		public static byte[] hexString2ByteNoSpace(String s) {
			int len = s.length();
			byte[] ret = new byte[len >>> 1];
			for (int i = 0; i <= len - 2; i += 2) {
				ret[i >>> 1] = (byte) (Integer.parseInt(s.substring(i, i + 2)
						.trim(), 16) & 0xFF);
			}
			return ret;
		}

		/**
		 * 把输入流转化一个字符串
		 * 
		 * @param in
		 *            输入流
		 * @return 字符串
		 * @throws IOException
		 */
		public static String inputStream2String(InputStream in)
				throws IOException {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			byte[] b = new byte[1024];
			int len = 0;
			while ((len = in.read(b)) != -1)
				out.write(b, 0, len);
			return new String(out.toByteArray());
		}

		/**
		 * 把字符串转换为utf8字节数据
		 * 
		 * @param src
		 *            utf8编码原字符串
		 * @return 字节数组
		 */
		public static byte[] string2Byte(String src) {
			byte[] ret = null;
			try {
				ret = src.getBytes("UTF8");
			} catch (UnsupportedEncodingException e) {
				throw new RuntimeException(e);
			}
			return ret;
		}

		/**
		 * 把utf8字节数据转换为字符串
		 * 
		 * @param src
		 *            utf8编码原字节数组
		 * @return 编码后的字符串
		 */
		public static String byte2String(byte[] src) {
			String ret = null;
			try {
				ret = new String(src, "UTF8");
			} catch (UnsupportedEncodingException e) {
				throw new RuntimeException(e);
			}
			return ret;
		}

		/**
		 * 把整形数转换为字节数组
		 * 
		 * @param i
		 * @return
		 */
		public static byte[] int2Byte(int i) {
			byte[] b = new byte[4];
			for (int m = 0; m < 4; m++, i >>= 8) {
				b[m] = (byte) (i & 0x000000FF); // 奇怪, 在C# 整型数是低字节在前 byte[]
												// bytes =
												// BitConverter.GetBytes(i);
												// 而在JAVA里，是高字节在前
			}
			return b;
		}
	}
}
